﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using RSPJ.Function;
using RSPJ.Struct;
using RSPJ.Windows;

namespace RSPJ.Windows
{
    public partial class KMean : Form
    {
        Files file;
        double[,,] dataArray;
        static List<int> Data = new List<int>();  //所选特征
        public KMean(Files file)
        {
            InitializeComponent();
            this.file = file.Clone();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < clbBands.Items.Count; i++)
            {
                if (clbBands.GetItemChecked(i))
                {
                    Data.Add(Convert.ToInt32(clbBands.GetItemText(clbBands.Items[i])));     //所选特征
                }
            }

            int clusternum = Convert.ToInt32(txtNum.Text);  //类的个数
            int featurenum = Data.Count;  //所选特征个数

            int[,] classification = new int[file.Head.Lines, file.Head.Samples];   //存储分类结果
            double[,] Classcenter = new double[clusternum, featurenum];  //类中心
            int[,,] temp = new int[clusternum, featurenum, 2];  //三维数组，存储每一类每个特征像素值之和、像素个数

            for (int s = 0; s < file.Head.Lines; s++)
            {
                for (int m = 0; m < file.Head.Samples; m++)
                {
                    Random ra = new Random();
                    int c = ra.Next(0, clusternum);   //随机生成一个0~(n-1)之间的数
                    classification[s, m] = c;   //随机赋一个值给每个像素
                    for (int j = 0; j < featurenum; j++)       //对应的类像素值和个数产生变化
                    {
                        temp[c, j, 0] += (int)file.IntArray[Data[j] - 1, s, m];   //sum加上对应波段像素值
                        temp[c, j, 1]++;                         //num+1
                        Classcenter[c, j] = Convert.ToDouble(temp[c, j, 0]) / temp[c, j, 1];  //计算类中心
                    }
                }
            }
            int flag;  //确定是否收敛的标记变量

            do
            {   //重新分类，直至收敛
                double[] Oldclassification = new double[clusternum];  //用于检验是否收敛的原始类
                for (int i = 0; i < clusternum; i++)
                { //记录每个类第一个特征处的类中心
                    Oldclassification[i] = Classcenter[i, 0];
                }


                for (int s = 0; s < file.Head.Lines; s++)
                {
                    for (int m = 0; m < file.Head.Samples; m++)
                    {
                        double[] d = new double[clusternum];
                        for (int i = 0; i < clusternum; i++)
                        {
                            for (int j = 0; j < featurenum; j++)
                            {
                                d[i] += Math.Pow(file.IntArray[Data[j] - 1, s, m] - Classcenter[i, j], 2);  //计算该像素到各个类中心的距离
                            }
                        }

                        double dmin = d[0];
                        int Newclass = 0;     //记录该像素新类
                        int Oldclass = classification[s, m];    //该像素原始类

                        for (int i = 1; i < clusternum; i++)   //找出距离该像素最近的类
                        {
                            if (d[i] < dmin)
                            {
                                dmin = d[i];
                                Newclass = i;
                            }
                        }
                        classification[s, m] = Newclass;                                         //改变该像素所处类别

                        for (int j = 0; j < featurenum; j++)    //重新分类
                        {
                            temp[Oldclass, j, 0] -=(int) file.IntArray[Data[j] - 1, s, m];   //每个特征抠出对应像素值
                            temp[Oldclass, j, 1]--;
                            temp[Newclass, j, 0] += (int)file.IntArray[Data[j] - 1, s, m];    //重新划分到的类加上该像素值
                            temp[Newclass, j, 1]++;

                            Classcenter[Oldclass, j] = (Convert.ToDouble(temp[Oldclass, j, 0])) / temp[Oldclass, j, 1];  //重新计算类中心
                            Classcenter[Newclass, j] = (Convert.ToDouble(temp[Newclass, j, 0])) / temp[Newclass, j, 1];
                        }
                    }
                }

                double[] Newclassification = new double[clusternum];  //用于检验是否收敛的新类
                for (int i = 0; i < clusternum; i++)
                {//将改变后的分类赋值给新类
                    Newclassification[i] = Classcenter[i, 0];
                }

                flag = 0;
                for (int i = 0; i < clusternum; i++)
                {
                    if (Math.Abs(Newclassification[i] - Oldclassification[i]) > 0.00000001)   //如果不收敛
                    {
                        flag = 1;
                    }
                }

            } while (flag == 1);

            if (cbx1.Checked == true)   //如果选择进行分类后处理
            {
                int[,] neighbor = new int[8, 2];    //邻接像素属于同一类的个数
                int retrainflag;    //是否满足碎斑处理结束条件
                do
                {
                    retrainflag = 0;
                    for (int j = 1; j < file.Head.Lines - 1; j++)
                    {
                        for (int k = 1; k < file.Head.Samples - 1; k++)
                        {
                            for (int t = 0; t < 8; t++)
                            {
                                neighbor[t, 0] = -1;
                                neighbor[t, 1] = 0;
                            }
                            int location = 0;
                            for (int m = j - 1; m < j + 2; m++)
                            {
                                for (int n = k - 1; n < k + 2; n++)
                                {
                                    if ((m == j) && (n == k))
                                        continue;
                                    else
                                    {
                                        int flg = 0;

                                        for (int i = 0; i < 8; i++)
                                        {
                                            if (neighbor[i, 0] == classification[m, n])
                                            {
                                                flg = 1;   //已存在该值
                                                neighbor[i, 1]++;
                                            }

                                        }
                                        if (flg == 0)
                                        {
                                            neighbor[location, 0] = classification[m, n];
                                            neighbor[location, 1]++;
                                            location++;
                                        }
                                    }
                                }
                            }
                            int flg1 = -1;
                            for (int s = 0; s < 8; s++)
                            {
                                if (neighbor[s, 1] >= 6)
                                {
                                    flg1 = neighbor[s, 0];
                                }
                            }
                            if (flg1 != -1)
                            {
                                classification[j, k] = flg1;
                                retrainflag = 1;
                            }

                        }
                    }
                    MessageBox.Show("succeed!");

                } while (retrainflag == 0);

            }


            file.Name = "KMeanResult";
            file.Head.Bands = 1;
            for (int i = 0; i < 1; i++)   //写入数据
            {
                for (int j = 0; j < file.Head.Lines; j++)
                {
                    for (int k = 0; k < file.Head.Samples; k++)
                    {
                        dataArray[i, j, k] = ((int)(255 / clusternum)) * (classification[j, k] + 1);
                        file.IntArray[i, j, k] = dataArray[i, j, k];
                    }
                }
            }

            using (ConvertData cd = new ConvertData(file))
            {
                if (cd.ShowDialog() == DialogResult.OK)
                {

                    GlobalData.fileList.Add(cd.file);
                    // 打开波段列表
                    if (WindowsStatus.availableBandsList == false)
                    {
                        AvailableBandsList bandsWindow = new AvailableBandsList();
                        WindowsStatus.availableBandsList = true;
                        bandsWindow.Show();
                    }
                    DialogResult = DialogResult.OK;
                    Close();
                }
            }
        }

        private void KMean_Shown(object sender, EventArgs e)
        {
            for (int i = 1; i <= file.Head.Bands; i++)
            {
                clbBands.Items.Add(i);
            }

            dataArray = new double[file.Head.Bands, file.Head.Lines, file.Head.Samples];
            for (int i = 0; i < file.Head.Bands; i++)
            {
                for (int j = 0; j < file.Head.Lines; j++)
                {
                    for (int k = 0; k < file.Head.Samples; k++)
                    {
                        dataArray[i, j, k] = file.IntArray[i, j, k];
                    }
                }
            }
        }
    }
}
